%load_ext pretty_jupyter

Importar Bibliotecas

import pandas as pd
import os
import numpy as np
# Worcloud
from PIL import Image
from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
# Gráficos
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import seaborn as sns

import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.express as px

# Salvar o gráfico como um arquivo HTML
import plotly.io as pio
# Calcular a correlação
from scipy.stats import pearsonr
from scipy.stats import spearmanr
import numpy as np
import statsmodels.api as sm
# tabset
import jinja2
get_ipython().run_line_magic('load_ext', 'pretty_jupyter')

Definir Diretório

os.chdir("C:/0.Projetos/5.Sistema_de_Recomendacao_MovieLens_2")

Carregar Arquivos

genome_treino= pd.read_pickle("C:/0.Projetos/5.Sistema_de_Recomendacao_MovieLens_2/Datasets/3.Datasets_Transformação/3.2_Datasets_Transformação_parte_2/genome_treino.pickle", compression='gzip')
genome_treino.head(3)
movieId tagId relevance tag
0 1 1 0.03200 007
1 1 2 0.02225 007 (series)
2 1 3 0.07000 18th century
tags_treino = pd.read_pickle("C:/0.Projetos/5.Sistema_de_Recomendacao_MovieLens_2/Datasets/2.Datasets_Limpeza/tags_treino.pickle", compression = "gzip")
tags_treino
userId movieId tag timestamp
0 134 89898 advertising 1521614243
1 134 89898 drugs 1521614238
2 134 89898 Russia 1521614240
3 134 182899 Action 1514209025
4 134 182899 Asia 1514209050
... ... ... ... ...
44612 330008 79091 nerds 1433358037
44613 330008 79091 supervillain 1433358009
44614 330008 81564 animation 1433357978
44615 330008 81564 funny 1433357989
44616 330008 81564 supervillain 1433357964

44617 rows × 4 columns

ratings_treino_transformado = pd.read_pickle("C:/0.Projetos/5.Sistema_de_Recomendacao_MovieLens_2/Datasets/3.Datasets_Transformação/3.1_Datasets_Transformação_parte_1/ratings_treino_transformado.pickle", compression = "gzip")
ratings_treino_transformado.head(3)
userId Numero_de_Avaliacoes_por_usuarios movieId Numero_de_Avaliacoes_por_Filme rating rating_medio_simples rating_medio_ponderado
0 5 43 47 1567 5.0 4.057754 3.286254
1 5 43 175 140 4.0 3.482143 1.258266
2 5 43 257 104 4.0 3.341346 1.032082
movies_treino_transformado = pd.read_pickle("C:/0.Projetos/5.Sistema_de_Recomendacao_MovieLens_2/Datasets/3.Datasets_Transformação/3.2_Datasets_Transformação_parte_2/movies_treino_transformado.pickle", compression = 'gzip')
movies_treino_transformado.head(3) 
movieId title genres Ano_do_filme titulo_sem_ano genres_separado
0 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy 1995 Toy Story Adventure
1 2 Jumanji (1995) Adventure|Children|Fantasy 1995 Jumanji Adventure
2 3 Grumpier Old Men (1995) Comedy|Romance 1995 Grumpier Old Men Comedy

Funções

Função 1: Calcula o Resumo Estatístico

def resumo_estatistico(tabela:pd.DataFrame, coluna:str) -> pd.DataFrame:

    # Calcula estatísticas descritivas usando agg
    resumo = tabela[coluna].agg(['count', 'mean','median', 'std', 'min', 'max' ]).round(2)

    # Renomeiar a coluna 'median' para 'median (50%)'
    resumo = resumo.rename(index={'median': 'median (50%)'})

    # Calcula percentis usando quantile
    percentis = tabela[coluna].quantile([0.25, 0.5, 0.75]).round(2)

    # Combina os resultados em um DataFrame único
    resumo = pd.concat([resumo, percentis.rename({0.25: '25%', 0.5: '50%', 0.75: '75%'})])

    display(resumo)

Função 2: Retorna a frequência e proporção dos valores únicos

def valores_unicos(tabela:pd.DataFrame, coluna:str) -> pd.DataFrame:
    
    # Calcula a contagem dos valores únicos usando value_counts
    contagem = tabela[coluna].value_counts().reset_index()

    # Renomeia as colunas para tornar o resultado mais claro
    contagem.columns = ['Valor_Único', 'Frequência']

    # Adiciona uma coluna de proporção em porcentagem
    contagem['Proporção (%)'] = (contagem['Frequência'] / contagem['Frequência'].sum()) * 100

    # Arredonda a coluna de proporção para 4 casas decimais
    contagem['Proporção (%)'] = contagem['Proporção (%)'].round(4)

    # Formata a coluna de proporção como porcentagem
    contagem['Proporção (%)'] = contagem['Proporção (%)'].map('{:.4f}%'.format)


    return contagem

1. Quantidade de usuários, de filmes e de gêneros

Nesta amostra, existem 7.943 clientes, 24.345 filmes e 19 gêneros de filmes.

quantidade_user = ratings_treino_transformado['userId'].nunique()
quantidade_filmes = ratings_treino_transformado['movieId'].nunique()
quantidade_generos = movies_treino_transformado['genres_separado'].nunique()
print(f"Quantidade de usuários: {quantidade_user} ")
print(f"Quantidade de filmes: {quantidade_filmes} ")
print(f"Quantidade de genero: {quantidade_generos} ")
Quantidade de usuários: 7943 
Quantidade de filmes: 24345 
Quantidade de genero: 19 

Gráfico: usuários, filmes e gêneros

# Criação do gráfico
plt.figure(figsize=(8, 4))

# Definição das posições dos pontos
x_positions = [0.5, 1.5, 2.5]
y_positions = [1, 1, 1]

# Definição das cores dos pontos
#colors = ['#06837f', 'orange'ou '#ffc675', '#6a0572']
#colors = ['#96c9c2','#ffc675' , '#b978b0']
colors = ['#91C6D3','#FFA051' , '#CB85FF']
# Definição dos tamanhos dos pontos
sizes = [15000, 15000, 15000]

# Criação dos pontos no gráfico
plt.scatter(x=x_positions, y=y_positions, s=sizes, color=colors)

# Definição dos limites dos eixos
plt.xlim(0, 3)
plt.ylim(0.9, 1.2)

# Adição de títulos e rótulos
plt.title('Quantidade de Usuários, Filmes e Gêneros', fontsize=18, weight=600, color='#333d29')
plt.text(0.5, 1, f'{quantidade_user}\nUsuários', va='center', ha='center', fontsize=18, weight=600, color='black')
plt.text(1.5, 1, f'{quantidade_filmes}\nFilmes', va='center', ha='center', fontsize=18, weight=600, color='black')
plt.text(2.5, 1, f'{quantidade_generos}\nGêneros', va='center', ha='center', fontsize=18, weight=600, color='black')
plt.text(0.5, 1.11, 'Usuários', va='center', ha='center', fontsize=17, weight=500, color='#1c2541')
plt.text(1.5, 1.11, 'Filmes', va='center', ha='center', fontsize=17, weight=500, color='#1c2541')
plt.text(2.5, 1.11, 'Gêneros', va='center', ha='center', fontsize=17, weight=500, color='#1c2541')

# Desliga a exibição dos eixos
plt.axis('off')

# Exibição do gráfico
plt.show()

2. Distribuição estatística de Ratings

A média de ratings é 3,52 e as notas mais dadas são 4, 3, 5 e 3.5 respectivamente. Estes valores mostram que os filmes tem uma avaliação intermediária.

Resumo Estatístico de Ratings

resumo_estatistico(ratings_treino_transformado, 'rating')
count           820508.00
mean                 3.52
median (50%)         3.50
std                  1.07
min                  0.50
max                  5.00
25%                  3.00
50%                  3.50
75%                  4.00
Name: rating, dtype: float64

Proporção dos Valores únicos de Ratings

valores_unicos(ratings_treino_transformado, 'rating')
Valor_Único Frequência Proporção (%)
0 4.0 213944 26.0746%
1 3.0 156350 19.0553%
2 5.0 114835 13.9956%
3 3.5 107438 13.0941%
4 4.5 75437 9.1939%
5 2.0 54051 6.5875%
6 2.5 43567 5.3098%
7 1.0 24483 2.9839%
8 0.5 15507 1.8899%
9 1.5 14896 1.8155%

Gráfico BoxPlot - Distribuição Rating

import seaborn as sns
import matplotlib.pyplot as plt

# Ajustar o estilo e a paleta de cores
sns.set(style="white", palette="muted")

# Ajustar a escala para melhor visualização
plt.figure(figsize=(9, 4))

# Criar o boxplot
ax = sns.boxplot(x=ratings_treino_transformado['rating'], 
                 color="#04819E",
                 medianprops={"color": "#FF7F00", "linewidth": 2},
                 showmeans=True,
                 meanprops={"markerfacecolor":"white", 
                            "markeredgecolor":"black",
                            "markersize":"10"})

# Adicionar legendas manuais
plt.plot([], [], color='#FF7F00', label='Mediana', linewidth=2)
plt.plot([], [], 'w^', label='Média', markersize=10, markeredgecolor="black")

# Adicionar título e rótulos aos eixos
plt.title('Distribuição de Rating', fontsize=18, fontweight='bold')
plt.xlabel('Rating', fontsize=14)
plt.ylabel('Contagem', fontsize=14)

# Exibir a legenda à esquerda
plt.legend(loc='upper right', fontsize=10, frameon=True, fancybox=True, shadow=True, borderpad=1)

# Ajustar a cor das bordas esquerda e direita
ax.spines['bottom'].set_color('#808080')  # definir a cor desejada para a borda esquerda
ax.spines['left'].set_color('#808080')  # definir a cor desejada para a borda direita
ax.spines['bottom'].set_linewidth(0.7)  # ajustar a largura da borda esquerda
ax.spines['left'].set_linewidth(0.7)  # ajustar a largura da borda direita

# Remover as bordas de cima e da direita
sns.despine(top=True, right=True)

# Ajustar os ticks dos eixos
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)

# Exibir o gráfico
plt.show()

Gráfico- Contagem de valores de Rating

import matplotlib.pyplot as plt
import seaborn as sns

# Criar um gráfico de contagem para a coluna ratings
plt.figure(figsize=(5, 4))
sns.set(style="whitegrid")
ax = sns.countplot(x=ratings_treino_transformado['rating'], color="#046D86")

# Adicionar título e rótulos aos eixos
plt.title('Contagem de ocorrências de cada valor de rating', fontsize=16, fontweight='bold')
plt.xlabel('Rating', fontsize=14)
plt.ylabel('Contagem', fontsize=14)

# Ajustar a cor das bordas
ax.spines['bottom'].set_color('#404040')
ax.spines['left'].set_color('#404040')

# Ajustar a largura das bordas 
ax.spines['bottom'].set_linewidth(0.9)
ax.spines['left'].set_linewidth(0.9)

# Adicionar bordas às barras
for patch in ax.patches:
    patch.set_edgecolor('#004050')  # cor da borda
    patch.set_linewidth(0.7)        # espessura da borda

# Remover as bordas de cima e da direita
sns.despine(top=True, right=True)

# Exibir o gráfico
plt.show()

3.Quantidade de filmes que um usuário avalia

Um usuário avalia em média 609 filmes e a mediana é 318. A maioria dos usuários faz 15 avaliações, seguidos de usuários que fazem 5.071 , 4.228, 4.135 e 16 avaliações, respectivamente.

Pensamos em duas hipóteses sobre os usuários que fazem 15 avaliações:
$H_0:$ Os usuários são novos no site, por isso, fizeram poucas avaliações.
$H_1:$ Os usuários utilizaram o site por um tempo e não ficaram satisfeitos. Por isso, deixaram de usá-lo.

Para entender qual é a hipótese mais provável, fizemos uma análise gráfica. Ao olhar o histograma, observa-se que a maioria das avaliações por usuários fica entre 0 e 1.000.
Por isso, criamos um outro gráfico cujo intervalo fica entre 0 e 1.000. E notamos que a partir de 40 avaliações por usuário, a contagem começa a diminuir.

Para complementar a análise gráfica e entender o motivo do número de avaliações diminuir com o passar do tempo, separamos o dataset em faixas e examinamos a média da coluna rating.

Faixa Média
Até 40 avaliações por usuário 3.70
De 41 às 999 avaliações por usuário 3.59
Acima de 1.000 avaliações por usuário 3.13

$\uparrow$ Contagem do Número de Avaliações por usuário $\ \ \ \ $ $\downarrow$ Nota dada (rating)

Observa-se que conforme aumenta a contagem número de avaliações por usuário, há uma diminuição da nota dada (rating). Isto pode ser resultado de uma insatisfação dos usuários com as recomendações $(H_1)$.

Logo, seria interessante a MovieLens investigar o comportamento destes usuários para extrair insights de como melhorar as recomendações.
Para isso, o site poderia:

  • Analisar o número de avaliações vs média (rating) ao longo do tempo: Isto seria interessante para entender se existe um padrão temporal no uso do site MovieLens. Exemplo: por quanto tempo um usuário utiliza ativamente o site?
  • Fazer segmentações: o MovieLens poderia segmentar os usuários por idade e gênero para descobrir como as notas dadas variam em cada grupo e assim, pensar em recomendações personalizadas para cada segmento de usuário.
  • </ul>
    Espera-se que após estas análises, o MovieLens melhore a média de ratings e aumenta o número de avaliações por usuário.

    ratings_treino_transformado.head()
    
    userId Numero_de_Avaliacoes_por_usuarios movieId Numero_de_Avaliacoes_por_Filme rating rating_medio_simples rating_medio_ponderado
    0 5 43 47 1567 5.0 4.057754 3.286254
    1 5 43 175 140 4.0 3.482143 1.258266
    2 5 43 257 104 4.0 3.341346 1.032082
    3 5 43 318 2948 4.0 4.415366 3.888469
    4 5 43 319 207 4.0 3.910628 1.708250

    Resumo Estatístico do Nº de Avaliações por Usuários

    resumo_estatistico(ratings_treino_transformado,'Numero_de_Avaliacoes_por_usuarios' )
    
    count           820508.00
    mean               609.36
    median (50%)       318.00
    std                821.60
    min                  1.00
    max               5071.00
    25%                122.00
    50%                318.00
    75%                733.00
    Name: Numero_de_Avaliacoes_por_usuarios, dtype: float64

    Rating por faixas

    filtro_0_40 = ratings_treino_transformado.loc[(ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] <= 40)]
    filtro_41_500 = ratings_treino_transformado.loc[
        (ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] >= 40) &
        (ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] <= 500)
    ]
    
    filtro_501_1000 = ratings_treino_transformado.loc[
        (ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] >= 501) &
        (ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] <= 1000)
    ]
    
    filtro_1001_1500 = ratings_treino_transformado.loc[
        (ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] >= 1001) &
        (ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] <= 1500)
    ]
    
    filtro_1501_2000 = ratings_treino_transformado.loc[
        (ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] >= 1501) &
        (ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] <= 2000)
    ]
    
    filtro_2001_3000 = ratings_treino_transformado.loc[
        (ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] >= 2001) &
        (ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] <= 3000)
    ]
    
    filtro_3001_4500 = ratings_treino_transformado.loc[
        (ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] >= 3001) &
        (ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] <= 4500)
    ]
    
    filtro_4501_5071 = ratings_treino_transformado.loc[
        (ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] >= 4501) &
        (ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] <= 5071)
    ]
    
    faixas = pd.DataFrame({
        'Faixas_Numero_de_avaliacoes':['0-40','41-500', '501-1000', '1001-1500', '1501-2000', '2001-3000', '3001-4500', '4501-5071'],
        'Faixas_Numero_de_avaliacoes2':[40,500, 1000, 1500, 2000,3000,4500, 5071],
        'Rating_por_faixa':[filtro_0_40['rating'].mean(), filtro_41_500['rating'].mean(),filtro_501_1000['rating'].mean(), filtro_1001_1500['rating'].mean(), filtro_1501_2000['rating'].mean(), filtro_2001_3000['rating'].mean(),filtro_3001_4500['rating'].mean(),filtro_4501_5071['rating'].mean()]
    })
    faixas
    
    Faixas_Numero_de_avaliacoes Faixas_Numero_de_avaliacoes2 Rating_por_faixa
    0 0-40 40 3.696145
    1 41-500 500 3.650309
    2 501-1000 1000 3.417410
    3 1001-1500 1500 3.235099
    4 1501-2000 2000 3.254429
    5 2001-3000 3000 2.961035
    6 3001-4500 4500 2.877094
    7 4501-5071 5071 2.658154

    Gráfico Número de avaliações por usuário e rating

    # Dados para o histograma
    histogram_data = ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios']
    
    # Dados para o grafico de linha
    df_linha = faixas
    
    # Criar o gráfico combo com histograma e linha
    fig = go.Figure()
    
    # Adicionar histograma
    fig.add_trace(go.Histogram(
        x=histogram_data,
        nbinsx=100,
        marker_color="#7D01D6",
        marker_line_color='white',
        marker_line_width=1.5,
        name='Distribuição do número de avaliações de filme por usuário',
        yaxis='y1'  # Associando ao eixo y1 (à esquerda)
    ))
    
    # Adicionar linha com médias de rating por faixa
    fig.add_trace(go.Scatter(
        x=df_linha['Faixas_Numero_de_avaliacoes2'],
        y=df_linha['Rating_por_faixa'],
        mode='lines+markers',
        line=dict(color='#FF5733', width=2.9),
        marker=dict(color='#FF5733', size=9),
        name='Média de Ratings por Faixa de Número de Avaliações por Usuário',
        xaxis='x',
        yaxis='y2'  # Associando ao eixo y2 (à direita)
    ))
    
    # Atualizar layout do gráfico
    fig.update_layout(
        width=950,
        height=550,
        title='Distribuição do número de avaliações de filme por usuário e Média de Ratings por Faixa',
        title_font=dict(size=20, family='Arial', color='black', weight='bold'),  # Tamanho e estilo do título
        xaxis_title='Número de avaliações de filme por usuário',
        yaxis_title='Contagem',
         xaxis=dict(
            tickmode='linear',
            tick0=0,
            dtick=500,
            tickfont=dict(size=12),
        ),
        yaxis=dict(
            title='Contagem',
            side='left',  # Posicionar à esquerda
            showgrid=False,
            showticklabels=True,
            tickfont=dict(size=12),
        ),
        yaxis2=dict(
            title='Média de Rating',
            overlaying='y',
            side='right',  # Posicionar à direita
            showgrid=False,
            showticklabels=True,
            tickfont=dict(size=12),
        ),
        font=dict(family="Arial", size=12),
        legend=dict(
            x=0.5,  # Posição horizontal da legenda em relação ao gráfico
            y=1.05,   # Posição vertical da legenda em relação ao gráfico
            traceorder='normal',
            font=dict(
                family='Arial',
                size=12,
                color='black'
            ),
            bgcolor='rgba(255, 255, 255, 0.5)',
            bordercolor='rgba(0, 0, 0, 0.4)',
            borderwidth=1
        ),
        showlegend=True,
        plot_bgcolor='white'
    )
    
    # Exibir o gráfico
    fig.show()
    
    # Salvar o gráfico como um arquivo HTML
    import plotly.io as pio
    pio.write_html(fig, file='Distribuicao_Numero_de_avaliacoes_por_usuario.html', auto_open=True)
    

    <iframe src="Distribuicao_Numero_de_avaliacoes_por_usuario.html", width="1050", height="600" ></iframe>

    Comparar as médias de quem avalia muito e pouco

    Vamos analisar a média da coluna rating dos usuários que avaliaram até 1.000 filmes e dos usuários que avaliaram mais de 1.000 filmes.

    Selecionar apenas até 1.000 avaliações por usuário

    filtro_1000 = ratings_treino_transformado.loc[(ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] <= 1000)]
    filtro_1000.head(3)
    
    userId Numero_de_Avaliacoes_por_usuarios movieId Numero_de_Avaliacoes_por_Filme rating rating_medio_simples rating_medio_ponderado
    0 5 43 47 1567 5.0 4.057754 3.286254
    2 751 469 47 1567 3.0 4.057754 3.286254
    4 1174 12 47 1567 5.0 4.057754 3.286254
    import pandas as pd
    
    # Definindo os intervalos e rótulos das faixas
    faixas_definidas = [
        (0, 40),
        (11, 80),
        (81, 100),
        (101, 150),
        (151, 200),
        (201, 250),
        (251, 300),
        (301, 350),
        (351, 400),
        (401, 550),
        (551, 650),
        (651, 700),
        (701, 800),
        (801, 1000)
    ]
    
    # Criando uma lista para armazenar os resultados
    faixas_data = []
    
    # Iterando sobre os intervalos
    for faixa in faixas_definidas:
        faixa_min, faixa_max = faixa
        filtro = ratings_treino_transformado.loc[
            (ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] >= faixa_min) &
            (ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'] <= faixa_max)
        ]
        faixa_label = f'{faixa_min}-{faixa_max}'
        rating_medio = filtro['rating'].mean()
        # Obtendo o último número da faixa
        ultimo_numero = faixa_max
        faixas_data.append({
            'Faixas_Numero_de_avaliacoes': faixa_label,
            'Faixas_Numero_de_avaliacoes2': ultimo_numero,
            'Rating_por_faixa': rating_medio
        })
    
    # Criando o DataFrame a partir da lista de dicionários
    faixas1 = pd.DataFrame(faixas_data)
    
    # Exibindo o DataFrame com as faixas, o último número da faixa e as médias de rating
    print(faixas1)
    
       Faixas_Numero_de_avaliacoes  Faixas_Numero_de_avaliacoes2  Rating_por_faixa
    0                         0-40                            40          3.696145
    1                        11-80                            80          3.729868
    2                       81-100                           100          3.747573
    3                      101-150                           150          3.722232
    4                      151-200                           200          3.678422
    5                      201-250                           250          3.679058
    6                      251-300                           300          3.576646
    7                      301-350                           350          3.585126
    8                      351-400                           400          3.559443
    9                      401-550                           550          3.447619
    10                     551-650                           650          3.466044
    11                     651-700                           700          3.389441
    12                     701-800                           800          3.383572
    13                    801-1000                          1000          3.383043
    
    # Dados para o histograma
    histogram_data = filtro_1000['Numero_de_Avaliacoes_por_usuarios']
    
    # Dados para o grafico de linha
    df_linha1 = faixas1
    
    # Criar o gráfico combo com histograma e linha
    fig = go.Figure()
    
    # Adicionar histograma
    fig.add_trace(go.Histogram(
        x=histogram_data,
        nbinsx=50,
        marker_color="#7D01D6",
        marker_line_color='white',
        marker_line_width=1.5,
        name='Distribuição do número de avaliações de filme por usuário',
        yaxis='y1'  # Associando ao eixo y1 (à esquerda)
    ))
    
    # Adicionar linha com médias de rating por faixa
    fig.add_trace(go.Scatter(
        x=df_linha1['Faixas_Numero_de_avaliacoes2'],
        y=df_linha1['Rating_por_faixa'],
        mode='lines+markers',
        line=dict(color='#FF5733', width=2.9),
        marker=dict(color='#FF5733', size=9),
        name='Média de Ratings por Faixa de Número de Avaliações por Usuário',
        xaxis='x',
        yaxis='y2'  # Associando ao eixo y2 (à direita)
    ))
    
    # Atualizar layout do gráfico
    fig.update_layout(
        width=1050,
        height=550,
        title='Distribuição do número de avaliações de filme por usuário e Média de Ratings por Faixa (até 1.000 avaliações)',
        title_font=dict(size=19, family='Arial', color='black', weight='bold'),  # Tamanho e estilo do título
        xaxis_title='Número de avaliações de filme por usuário',
        yaxis_title='Contagem',
         xaxis=dict(
            tickmode='linear',
            tick0=0,
            dtick=50,
            tickfont=dict(size=12),
        ),
        yaxis=dict(
            title='Contagem',
            side='left',  # Posicionar à esquerda
            showgrid=False,
            showticklabels=True,
            tickfont=dict(size=12),
        ),
        yaxis2=dict(
            title='Média de Rating',
            overlaying='y',
            side='right',  # Posicionar à direita
            showgrid=False,
            showticklabels=True,
            tickfont=dict(size=12),
        ),
        font=dict(family="Arial", size=12),
        legend=dict(
            x=0.5,  # Posição horizontal da legenda em relação ao gráfico
            y=1.05,   # Posição vertical da legenda em relação ao gráfico
            traceorder='normal',
            font=dict(
                family='Arial',
                size=12,
                color='black'
            ),
            bgcolor='rgba(255, 255, 255, 0.5)',
            bordercolor='rgba(0, 0, 0, 0.4)',
            borderwidth=1
        ),
        showlegend=True,
        plot_bgcolor='white'
    )
    
    # Exibir o gráfico
    fig.show()
    
    # Salvar o gráfico como um arquivo HTML
    import plotly.io as pio
    pio.write_html(fig, file='Distribuicao_Numero_de_avaliacoes_por_usuario_até_1000.html', auto_open=True)
    

    <iframe src="C:/0.Projetos/5.Sistema_de_Recomendacao_MovieLens_2/Imagens/Análise_Descritiva/Q.3/Distribuicao_Numero_de_avaliacoes_por_usuario_até_1000.html", width="1070", height="600" ></iframe>

    4. Existe relação entre o número de avaliações por usuário e a nota dada ?

    O objetivo desta análise é complementar o tópico 3. O resultado mostra que existe uma relação negativa , fraca, porém significativa entre a nota dada pelo usuário (rating) e o número de avaliações por usuário. Ou seja, conforme o número de avaliações aumenta, rating dimimui. O resultado destas correlações também é um indicativo de que com o passar do tempo, o usuário fica insatisfeito com as recomendações, dando uma nota menor nas avaliações dos filmes.
    Conforme o resultado anterior, este também sinaliza que a Movilens precisa melhorar as recomendações dos filmes e encontrar maneiras de reter o usuário por mais tempo. Este tipo de análise também poderia ser feita por sites como NetFlix.</mark>

    # Olhar as primeiras linhas da tabela que será usada
    ratings_treino_transformado.head()
    
    userId Numero_de_Avaliacoes_por_usuarios movieId Numero_de_Avaliacoes_por_Filme rating rating_medio_simples rating_medio_ponderado
    0 5 43 47 1567 5.0 4.057754 3.286254
    1 5 43 175 140 4.0 3.482143 1.258266
    2 5 43 257 104 4.0 3.341346 1.032082
    3 5 43 318 2948 4.0 4.415366 3.888469
    4 5 43 319 207 4.0 3.910628 1.708250

    Correlação

    Correlação de Spearman

    correlacao_avaliacao1= spearmanr(ratings_treino_transformado['rating'], ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'])
    print("Coeficiente de correlação de Spearman:", correlacao_avaliacao1.statistic)
    print("Valor-p:", correlacao_avaliacao1.pvalue)
    
    Coeficiente de correlação de Spearman: -0.20686186680073743
    Valor-p: 0.0
    

    Correlação de Pearson

    correlacao_avaliacao2 = pearsonr(ratings_treino_transformado['rating'], ratings_treino_transformado['Numero_de_Avaliacoes_por_usuarios'])
    print("Coeficiente de correlação de Pearson:", correlacao_avaliacao2.statistic)
    print("Valor-p:", correlacao_avaliacao2.pvalue)
    
    Coeficiente de correlação de Pearson: -0.19686933202479695
    Valor-p: 0.0
    

    Gráfico BoxPlot

    Para fazer o gráfico, vamos utilizar o rating médio ponderado e agrupá-lo em intervalos de 0,5.

    # Definindo os intervalos de 0.5 em 0.5 de 0 a 5
    bins = np.arange(0, 5.5, 0.5)
    
    # Função para arredondar para o intervalo mais próximo de 0,5
    def arredondar(number):
        return round(number * 2) / 2
    
    df = ratings_treino_transformado.copy()
    # Aplicando a função ao DataFrame
    df['media_ponderada_arredondada'] = df['rating_medio_ponderado'].apply(arredondar)
    
    # Olhar a tabela para ver se deu certo
    df.head()
    
    userId Numero_de_Avaliacoes_por_usuarios movieId Numero_de_Avaliacoes_por_Filme rating rating_medio_simples rating_medio_ponderado media_ponderada_arredondada
    0 5 43 47 1567 5.0 4.057754 3.286254 3.5
    1 5 43 175 140 4.0 3.482143 1.258266 1.5
    2 5 43 257 104 4.0 3.341346 1.032082 1.0
    3 5 43 318 2948 4.0 4.415366 3.888469 4.0
    4 5 43 319 207 4.0 3.910628 1.708250 1.5
    # Criar o gráfico de dispersão
    plt.figure(figsize=(16, 8))
    sns.boxplot(x= df['media_ponderada_arredondada'], y= df['Numero_de_Avaliacoes_por_usuarios'], color='#FF7F00')
    plt.ylabel('Número de Avaliações por usuário', fontsize=16, weight='bold')
    plt.xlabel('Ratings Médio Ponderado (agrupado)', fontsize=16, weight='bold')
    plt.title('Distribuição do Número de Avaliações por usuário em Diferentes Ratings', fontsize=18, weight='bold', pad=20)
    
    # Remover as linhas de grade superior e direita
    sns.despine()
    
    plt.xticks(fontsize=14)
    plt.yticks(fontsize=14)
    
    plt.tight_layout()
    plt.show()
    

    5. Quais filmes possuem mais avaliações?

    Observa-se que a maioria dos filmes mais avaliados são do final da década de 90 e início dos anos 2000. O gênero em sua maioria é Ação, Comédia e Crime.
    Os filmes mais avaliados são, respectivamente: The Shawshank Redemption (1994) ; Forrest Gump (1994) e Pulp Fiction (1994).
    Mas ao olhar a nuvem de palavras, vemos outros filmes se destacando: Star Wars, Harry Potter, Batman e Lord of Ring. O que eles tem em comum é que todos tem continuações. Então, se analisarmos as sagas como um todo, esses filmes também são muito avaliados.

    Olhar as tabelas que serão utilizadas

    Vamos utilizar algumas colunas das tabelas movies_treino_transformado e ratings_treino_transformado.

    # Olhar as primeiras linhas da tabela que será ultilizada
    movies_treino_transformado.head()
    
    movieId title genres Ano_do_filme titulo_sem_ano genres_separado
    0 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy 1995 Toy Story Adventure
    1 2 Jumanji (1995) Adventure|Children|Fantasy 1995 Jumanji Adventure
    2 3 Grumpier Old Men (1995) Comedy|Romance 1995 Grumpier Old Men Comedy
    3 4 Waiting to Exhale (1995) Comedy|Drama|Romance 1995 Waiting to Exhale Comedy
    4 5 Father of the Bride Part II (1995) Comedy 1995 Father of the Bride Part II Comedy
    # Olhar as primeiras linhas da tabela que será ultilizada
    ratings_treino_transformado.head()
    
    userId Numero_de_Avaliacoes_por_usuarios movieId Numero_de_Avaliacoes_por_Filme rating rating_medio_simples rating_medio_ponderado
    0 5 43 47 1567 5.0 4.057754 3.286254
    1 5 43 175 140 4.0 3.482143 1.258266
    2 5 43 257 104 4.0 3.341346 1.032082
    3 5 43 318 2948 4.0 4.415366 3.888469
    4 5 43 319 207 4.0 3.910628 1.708250

    Selecionar as colunas de interesse

    A seguir, selecionaremos as colunas de interesse, para em seguida fazer a união das tabelas.

    # Criar uma subtabela de 'movies_genero_separado
    tmp_movie = movies_treino_transformado[['movieId', 'title' , 'titulo_sem_ano', 'genres_separado']]
    tmp_movie.head(3)
    
    movieId title titulo_sem_ano genres_separado
    0 1 Toy Story (1995) Toy Story Adventure
    1 2 Jumanji (1995) Jumanji Adventure
    2 3 Grumpier Old Men (1995) Grumpier Old Men Comedy
    # Criar uma subtabela de 'ratings_data_hora3'
    tmp_ratings = ratings_treino_transformado[['movieId','Numero_de_Avaliacoes_por_Filme']]
    tmp_ratings.head(3)
    
    movieId Numero_de_Avaliacoes_por_Filme
    0 47 1567
    1 175 140
    2 257 104

    Unir as tabelas

    Após selecionar as colunas de interesse, vamos unir estas tabelas. Em seguida, removeremos as linhas duplicadas e organizaremos as tabelas de forma decrescente.

    # Unir as subtabelas
    filmes_mais_avaliados1 = pd.merge(tmp_movie , tmp_ratings, on='movieId' , how='right' )
    filmes_mais_avaliados1.head(3) 
    
    movieId title titulo_sem_ano genres_separado Numero_de_Avaliacoes_por_Filme
    0 47 Seven (a.k.a. Se7en) (1995) Seven (a.k.a. Se7en) Mystery 1567
    1 175 Kids (1995) Kids Drama 140
    2 257 Just Cause (1995) Just Cause Mystery 104
    # Apagar tabelas temporarias (subtabelas)
    del tmp_movie , tmp_ratings
    
    # Remover as linhas duplicadas
    filmes_mais_avaliados2 = filmes_mais_avaliados1.drop_duplicates(subset='title')
    
    # Organizar de forma decrescente
    filmes_mais_avaliados3 = filmes_mais_avaliados2.sort_values(by='Numero_de_Avaliacoes_por_Filme', ascending=False)
    filmes_mais_avaliados3
    
    movieId title titulo_sem_ano genres_separado Numero_de_Avaliacoes_por_Filme
    3 318 Shawshank Redemption, The (1994) Shawshank Redemption, The Crime 2948
    6 356 Forrest Gump (1994) Forrest Gump Comedy 2700
    47 296 Pulp Fiction (1994) Pulp Fiction Comedy 2609
    31 2571 Matrix, The (1999) Matrix, The Action 2578
    10 593 Silence of the Lambs, The (1991) Silence of the Lambs, The Crime 2512
    ... ... ... ... ... ...
    330142 27480 Dead or Alive 2: Tôbôsha (2000) Dead or Alive 2: Tôbôsha Action 1
    330143 27549 Dead or Alive: Final (2002) Dead or Alive: Final Comedy 1
    99917 6588 And Now... Ladies and Gentlemen... (2002) And Now... Ladies and Gentlemen... Romance 1
    330161 31932 Fallen Angel (1945) Fallen Angel Crime 1
    820406 165471 The Ring (1984) The Ring Drama 1

    24326 rows × 5 columns

    Tabela com os 30 filmes que possuem mais avaliações

    Agora, nós temos a tabela final com os filmes que possuem mais avaliações.

    # Selecionar as 30 primeiras linhas
    filmes_mais_avaliados4 = filmes_mais_avaliados3.head(30) 
    filmes_mais_avaliados4
    
    movieId title titulo_sem_ano genres_separado Numero_de_Avaliacoes_por_Filme
    3 318 Shawshank Redemption, The (1994) Shawshank Redemption, The Crime 2948
    6 356 Forrest Gump (1994) Forrest Gump Comedy 2700
    47 296 Pulp Fiction (1994) Pulp Fiction Comedy 2609
    31 2571 Matrix, The (1999) Matrix, The Action 2578
    10 593 Silence of the Lambs, The (1991) Silence of the Lambs, The Crime 2512
    46 260 Star Wars: Episode IV - A New Hope (1977) Star Wars: Episode IV - A New Hope Action 2342
    9 527 Schindler's List (1993) Schindler's List Drama 2070
    35 2959 Fight Club (1999) Fight Club Action 2049
    93 480 Jurassic Park (1993) Jurassic Park Action 1984
    57 1196 Star Wars: Episode V - The Empire Strikes Back... Star Wars: Episode V - The Empire Strikes Back Action 1942
    114 4993 Lord of the Rings: The Fellowship of the Ring,... Lord of the Rings: The Fellowship of the Ring,... Adventure 1915
    53 858 Godfather, The (1972) Godfather, The Crime 1858
    258 1 Toy Story (1995) Toy Story Adventure 1848
    119 7153 Lord of the Rings: The Return of the King, The... Lord of the Rings: The Return of the King, The Action 1834
    303 1210 Star Wars: Episode VI - Return of the Jedi (1983) Star Wars: Episode VI - Return of the Jedi Action 1819
    58 1198 Raiders of the Lost Ark (Indiana Jones and the... Raiders of the Lost Ark (Indiana Jones and the... Action 1814
    88 110 Braveheart (1995) Braveheart Action 1791
    200 5952 Lord of the Rings: The Two Towers, The (2002) Lord of the Rings: The Two Towers, The Adventure 1786
    44 50 Usual Suspects, The (1995) Usual Suspects, The Crime 1774
    264 589 Terminator 2: Judgment Day (1991) Terminator 2: Judgment Day Action 1723
    34 2858 American Beauty (1999) American Beauty Drama 1663
    319 1270 Back to the Future (1985) Back to the Future Adventure 1613
    30 2028 Saving Private Ryan (1998) Saving Private Ryan Action 1570
    0 47 Seven (a.k.a. Se7en) (1995) Seven (a.k.a. Se7en) Mystery 1567
    83 79132 Inception (2010) Inception Action 1561
    1040 780 Independence Day (a.k.a. ID4) (1996) Independence Day (a.k.a. ID4) Action 1550
    81 58559 Dark Knight, The (2008) Dark Knight, The Action 1548
    943 150 Apollo 13 (1995) Apollo 13 Adventure 1509
    261 457 Fugitive, The (1993) Fugitive, The Thriller 1485
    267 608 Fargo (1996) Fargo Comedy 1469

    Gráfico com os 30 filmes que possuem mais avaliações

    # Criar o gráfico de barras horizontais
    plt.figure(figsize=(10, 8))
    plt.barh(filmes_mais_avaliados4['title'], filmes_mais_avaliados4['Numero_de_Avaliacoes_por_Filme'], color='#FFA051')
    
    # Adicionar um espaçamento entre as barras
    plt.gca().invert_yaxis()
    plt.tight_layout()
    
    # Adicionar rótulos e título
    plt.xlabel('Número de Avaliações por Filme', fontsize=12)
    plt.ylabel('Título do Filme', fontsize=12)
    plt.title('Os 30 filmes que possuem mais avaliações', fontsize=14)
    
    # Remover grades de fundo e bordas do gráfico
    plt.grid(False)
    plt.box(False)
    
    # Aumentar o tamanho da fonte dos rótulos do eixo x e y
    plt.xticks(fontsize=10)
    plt.yticks(fontsize=10)
    
    # Exibir o gráfico
    plt.show()
    

    Nuvem de palavras 1

    Além do gráfico de barras feito acima, vamos criar 2 nuvens de palavras para representar os filmes mais assitidos.
    A Nuvem de palavras 1 contém os 50 filmes mais avaliados.

    Preparar a base 1

    # Olhar a tabela criada acima
    #filmes_mais_avaliados3
    
    # Selecionar os 50 primeiros valores únicos da coluna 'title'
    top_50_titulos1 = filmes_mais_avaliados3['titulo_sem_ano'].unique()[:50]
    
    # Filtrr o DataFrame para selecionar as linhas correspondentes aos 50 primeiros valores únicos de 'title'
    top_50_titulos2 = filmes_mais_avaliados3[filmes_mais_avaliados3['titulo_sem_ano'].isin(top_50_titulos1) ] 
    top_50_titulos2.head()
    
    movieId title titulo_sem_ano genres_separado Numero_de_Avaliacoes_por_Filme
    3 318 Shawshank Redemption, The (1994) Shawshank Redemption, The Crime 2948
    6 356 Forrest Gump (1994) Forrest Gump Comedy 2700
    47 296 Pulp Fiction (1994) Pulp Fiction Comedy 2609
    31 2571 Matrix, The (1999) Matrix, The Action 2578
    10 593 Silence of the Lambs, The (1991) Silence of the Lambs, The Crime 2512
    # Concatena todos os títulos em uma única string
    todos_titulos = ' '.join(top_50_titulos2['titulo_sem_ano'])
    
    print("Quantidade de palavras:", len(todos_titulos))
    
    Quantidade de palavras: 1130
    

    Nuvem 1

    # Lista de Stopword
    stop_words = set(STOPWORDS)
    
    # Gerar a WordCloud
    wordcloud_titulo1 = WordCloud(stopwords = stop_words,
                                 background_color = 'white' , 
                                 width = 1600 , height = 800).generate(todos_titulos)
    
    # Plota a WordCloud
    plt.figure(figsize=(10, 6))
    plt.imshow(wordcloud_titulo1, interpolation='bilinear')
    plt.axis('off')
    plt.show()                             
    
    # Salvar wordcloud 
    #wordcloud_titulo.to_file("wordcloud_titulo1.png")
    
    <wordcloud.wordcloud.WordCloud at 0x24a23a5c410>

    Nuvem de palavras 2

    A Nuvem de palavras 2 contém os 300 filmes mais bem avaliados.Vamos utilizar uma máscara para que a nuvem fique com o formato de uma claquete de cinema.

    Primeiro, vamos preparar a base selecionando os filmes e concatenando-os em uma úniva string.

    # Selecionar os 300 primeiros valores únicos da coluna 'title'
    top_300_titulos1 = filmes_mais_avaliados3['titulo_sem_ano'].unique()[:300]
    
    # Filtra o DataFrame para selecionar as linhas correspondentes aos 300 primeiros valores únicos de 'title'
    top_300_titulos2 = filmes_mais_avaliados3[filmes_mais_avaliados3['titulo_sem_ano'].isin(top_300_titulos1) ] 
    top_300_titulos2.head()
    
    movieId title titulo_sem_ano Numero_de_Avaliacoes_por_Filme
    3 318 Shawshank Redemption, The (1994) Shawshank Redemption, The 2948
    6 356 Forrest Gump (1994) Forrest Gump 2700
    47 296 Pulp Fiction (1994) Pulp Fiction 2609
    31 2571 Matrix, The (1999) Matrix, The 2578
    10 593 Silence of the Lambs, The (1991) Silence of the Lambs, The 2512
    # Concatena todos os títulos em uma única string
    todos_titulos1 = ' '.join(top_300_titulos2['titulo_sem_ano'])
    
    print(f"Quantidade de palavras: {len(todos_titulos1)} , quantidade de palavras únicas:{len(set(todos_titulos1))}")
    
    Quantidade de palavras: 6106 , quantidade de palavras únicas:74
    
    mascara_1 = np.array(Image.open("C:/0.Projetos/5.Sistema_de_Recomendação_MovieLens_2/Imagens/Análise_Descritiva/Mascaras/mascara_1.png" ))
    
    # Lista de Stopword
    stop_words = set(STOPWORDS)
        
    # Gerar a word_cloud
    wordcloud_titulo4b = WordCloud(stopwords = stop_words,
                                 background_color = 'white', 
                                 mask = mascara_1,
                                 width = 1000 , height = 1000,
                                 contour_color='black',
                                 contour_width=1,
                                 min_font_size= 6,
                                 color_func=lambda *args, **kwargs: "black").generate(todos_titulos1)
    
    # Plotar a WordCloud
    plt.figure(figsize=(10, 10))
    plt.imshow(wordcloud_titulo4b)
    plt.axis('off')
    plt.show()
    
    # Salvar wordcloud 
    wordcloud_titulo.to_file("wordcloud_titulo1b.png")
    
    <wordcloud.wordcloud.WordCloud at 0x24a23a5c410>

    6.Quais filmes possuem as maiores notas?

    Ao analisar a nota, observamos um resultado semelhante ao tópico anterior.Os filmes mais bem avaliados são: The Shawshank Redemption (1994), Pulp Fiction (1994), Matrix (1999) e The Godfather (1972).
    Observa-se que a maioria dos filmes com as maiores notas são da década de 70 ao final da década 90. Ou seja, são filmes mais antigos do que se comparado ao tópico anterior.

    E, os gêneros que se destacam são comédia, drama e crime.

    Preparar a base

    # Selecionar as colunas de interesse
    tmp_rating = ratings_treino_transformado[['movieId', 'rating_medio_ponderado']]
    tmp_movies = movies_treino_transformado[['movieId', 'title', 'titulo_sem_ano', 'genres_separado']]
    
    # Unir as tabelas
    tmp_merge = pd.merge( tmp_movies, tmp_rating, on='movieId', how='inner')
    tmp_merge.head(3)
    
    movieId title titulo_sem_ano genres_separado rating_medio_ponderado
    0 1 Toy Story (1995) Toy Story Adventure 3.264437
    1 1 Toy Story (1995) Toy Story Adventure 3.264437
    2 1 Toy Story (1995) Toy Story Adventure 3.264437
    # Remover as linhas duplicadas de "title"
    top_rating = tmp_merge.drop_duplicates( subset=['title'])
    
    # Organizar de forma decrescente
    top_rating1 = top_rating.sort_values(by='rating_medio_ponderado', ascending=False)
    
    # Selecionar os Top 30
    top_rating2 = top_rating1.head(30)
    

    Tabela com os 30 filmes com os maiores rating médio (ponderado)

    # Os 30 filmes com as maiores notas
    top_rating2
    
    movieId title titulo_sem_ano genres_separado rating_medio_ponderado
    64993 318 Shawshank Redemption, The (1994) Shawshank Redemption, The Crime 3.888469
    58904 296 Pulp Fiction (1994) Pulp Fiction Comedy 3.650467
    351123 2571 Matrix, The (1999) Matrix, The Action 3.630555
    150000 858 Godfather, The (1972) Godfather, The Crime 3.621123
    105900 527 Schindler's List (1993) Schindler's List Drama 3.583505
    122380 593 Silence of the Lambs, The (1991) Silence of the Lambs, The Crime 3.578315
    75357 356 Forrest Gump (1994) Forrest Gump Comedy 3.565995
    387793 2959 Fight Club (1999) Fight Club Action 3.549180
    18128 50 Usual Suspects, The (1995) Usual Suspects, The Crime 3.537581
    51068 260 Star Wars: Episode IV - A New Hope (1977) Star Wars: Episode IV - A New Hope Action 3.533020
    189914 1196 Star Wars: Episode V - The Empire Strikes Back... Star Wars: Episode V - The Empire Strikes Back Action 3.459020
    497792 4993 Lord of the Rings: The Fellowship of the Ring,... Lord of the Rings: The Fellowship of the Ring,... Adventure 3.446509
    563060 7153 Lord of the Rings: The Return of the King, The... Lord of the Rings: The Return of the King, The Action 3.433436
    661432 58559 Dark Knight, The (2008) Dark Knight, The Action 3.425891
    700561 79132 Inception (2010) Inception Action 3.397391
    527340 5952 Lord of the Rings: The Two Towers, The (2002) Lord of the Rings: The Two Towers, The Adventure 3.389858
    193095 1198 Raiders of the Lost Ark (Indiana Jones and the... Raiders of the Lost Ark (Indiana Jones and the... Action 3.374533
    378887 2858 American Beauty (1999) American Beauty Drama 3.354477
    25991 110 Braveheart (1995) Braveheart Action 3.299617
    206597 1221 Godfather: Part II, The (1974) Godfather: Part II, The Crime 3.296134
    128220 608 Fargo (1996) Fargo Comedy 3.295884
    200290 1210 Star Wars: Episode VI - Return of the Jedi (1983) Star Wars: Episode VI - Return of the Jedi Action 3.288476
    16120 47 Seven (a.k.a. Se7en) (1995) Seven (a.k.a. Se7en) Mystery 3.286254
    0 1 Toy Story (1995) Toy Story Adventure 3.264437
    303309 2028 Saving Private Ryan (1998) Saving Private Ryan Action 3.250819
    118034 589 Terminator 2: Judgment Day (1991) Terminator 2: Judgment Day Action 3.245101
    466201 4226 Memento (2000) Memento Mystery 3.244198
    188654 1193 One Flew Over the Cuckoo's Nest (1975) One Flew Over the Cuckoo's Nest Drama 3.241064
    371855 2762 Sixth Sense, The (1999) Sixth Sense, The Drama 3.229391
    272623 1704 Good Will Hunting (1997) Good Will Hunting Drama 3.209846
    del tmp_merge, tmp_movies, tmp_rating
    

    Gráfico com os Filmes com as maiores rating médio (ponderado)

    # Criar o gráfico de barras horizontais
    plt.figure(figsize=(10, 8))
    plt.barh(top_rating2['title'], top_rating2['rating_medio_ponderado'], color='#03647A')
    
    # Adicione um espaçamento entre as barras
    plt.gca().invert_yaxis()
    plt.tight_layout()
    
    # Adicione rótulos e título
    plt.xlabel('Rating Médio (Ponderado)', fontsize=12)
    plt.ylabel('Título do Filme', fontsize=12)
    plt.title('Os 30 Filmes com as maiores avaliações ponderadas', fontsize=14)
    
    # Remova grades de fundo e bordas do gráfico
    plt.grid(False)
    plt.box(False)
    
    # Aumente o tamanho da fonte dos rótulos do eixo x e y
    plt.xticks(fontsize=10)
    plt.yticks(fontsize=10)
    
    # Exiba o gráfico
    plt.show()
    

    Nuvem de Palavras - Rating Medio Ponderado

    Nuvem 1 - Rating Médio Ponderado

    # Selecionar os 50 primeiros valores únicos da coluna 'title'
    top_titulos_rating = top_rating1['titulo_sem_ano'].unique()[:50]
    
    # Filtra o DataFrame para selecionar as linhas correspondentes aos 50 primeiros valores únicos de 'title'
    top_titulos_rating1 = top_rating1[top_rating1['titulo_sem_ano'].isin(top_titulos_rating) ] 
    
    # Concatena todos os títulos em uma única string
    todos_titulos_rating = ' '.join(top_titulos_rating1['titulo_sem_ano'])
    
    print(f"Quantidade de palavras: {len(todos_titulos_rating)} , quantidade de palavras únicas:{len(set(todos_titulos_rating))}")
    
    Quantidade de palavras: 1214 , quantidade de palavras únicas:59
    
    # Lista de Stopword
    stop_words = set(STOPWORDS)
    
    # Gerar a WordCloud
    wordcloud_titulo_rating2 = WordCloud(stopwords = stop_words,
                                 background_color = 'white' , 
                                 width = 1600 , height = 800).generate(todos_titulos_rating)
    
    # Plota a WordCloud
    plt.figure(figsize=(10, 6))
    plt.imshow(wordcloud_titulo_rating2, interpolation='bilinear')
    plt.axis('off')
    plt.show()    
    

    Nuvem 2 - rating médio ponderado

    # Selecionar os 300 primeiros valores únicos da coluna 'title'
    top_titulos_rating = top_rating1['titulo_sem_ano'].unique()[:300]
    
    # Filtra o DataFrame para selecionar as linhas correspondentes aos 300 primeiros valores únicos de 'title'
    top_titulos_rating1 = top_rating1[top_rating1['titulo_sem_ano'].isin(top_titulos_rating) ] 
    
    # Concatena todos os títulos em uma única string
    todos_titulos_rating = ' '.join(top_titulos_rating1['titulo_sem_ano'])
    
    print(f"Quantidade de palavras: {len(todos_titulos_rating)} , quantidade de palavras únicas:{len(set(todos_titulos_rating))}")
    
    mascara_7 = np.array(Image.open("C:/0.Projetos/5.Sistema_de_Recomendação_MovieLens_2/Imagens/Análise_Descritiva/Mascaras/mascara_7.png" ))
    
    # Lista de Stopword
    stop_words = set(STOPWORDS)
        
    # Gerar a word_cloud
    wordcloud_titulo_rating2 = WordCloud(stopwords = stop_words,
                                 background_color = 'white', 
                                 mask = mascara_1,
                                 contour_color='black',
                                 contour_width=1,
                                 width = 1000 ,
                                 height = 1000).generate(todos_titulos_rating)
    
    imagem_colorida_rating = ImageColorGenerator(mascara_7)
    wordcloud_titulo_rating2.recolor(color_func=imagem_colorida_rating)                             
    
    # Plotar a WordCloud
    plt.figure(figsize=(10, 10))
    plt.imshow(wordcloud_titulo_rating2)
    plt.axis('off')
    plt.show()
    

    7. Quais gêneros possuem mais avaliações? Quais gêneros possuem as maiores notas?

    Os gêneros que possuem os maiores rating médio ponderado são respectivamente: Crime, Aventura e Mistério, Sci-Fi e Horror.
    Já os gêneros que possuem os maiores números de avaliações são respectivamente: Crime, Aventura, Mistério, Ação e Sci-Fi. Observa-se que os dois resultados são muito semelhantes

    Estes resultados também foram encontrados por Lu e Waterman (2005). Os pesquisadores descobriram que os gêneros cinematográficos "propensos à violência" (como "ação", "aventura", "ficção científica" e "terror") aumentaram consideravelmente sua prevalência entre os 20 filmes de maior bilheteria dos EUA no período de 1967 a 2004.

    Uma possível explicação encontrada pelos pesquisadores é que estes gêneros aumentaram o uso de tecnologia nos filmes.

    Vale ressaltar que o estudo foca nos filmes de maior bilheteria, cujo público alvo são os jovens, conforme será explicado nos próximos tópicos.

    Apesar do resultado não ser abrangente, ele ajuda a explicar o porquê destes gêneros terem as maiores notas e mais avaliações.

    Preparar a tabela

    # Selecionar as colunas de interesse
    tmp_movie = movies_treino_transformado[['movieId', 'genres_separado' ]]
    tmp_ratings = ratings_treino_transformado[['movieId','Numero_de_Avaliacoes_por_Filme', 'rating_medio_ponderado']]
    
    # Unir as tabelas 
    generos_ratings1 = pd.merge(tmp_movie , tmp_ratings, on='movieId' , how='right' )
    generos_ratings1.head(3)
    
    movieId genres_separado Numero_de_Avaliacoes_por_Filme rating_medio_ponderado
    0 47 Mystery 1567 3.286254
    1 175 Drama 140 1.258266
    2 257 Mystery 104 1.032082
    generos_ratings2 = generos_ratings1.drop_duplicates(subset=['genres_separado']).sort_values(by=['rating_medio_ponderado'], ascending= False)
    
    #del tmp_movie,tmp_ratings,generos_ratings1
    

    Tabela com gêneros dos filmes, nº de avaliações e rating médio ponderado

    generos_ratings2
    
    movieId genres_separado Numero_de_Avaliacoes_por_Filme rating_medio_ponderado
    3 318 Crime 2948 3.888469
    114 4993 Adventure 1915 3.446509
    0 47 Mystery 1567 3.286254
    132 109487 Sci-Fi 1002 3.084144
    64 1258 Horror 981 2.992502
    7 380 Action 1243 2.693046
    297 1199 Fantasy 457 2.439924
    278 913 Film-Noir 382 2.318216
    269 745 Animation 364 2.270124
    770 128360 Western 286 1.914850
    4 319 Comedy 207 1.708250
    1 175 Drama 140 1.258266
    17 1147 Documentary 94 1.153270
    810 166024 (no genres listed) 77 1.093831
    273 900 Musical 92 1.068638
    11 662 Thriller 74 0.826220
    1147 1658 Romance 63 0.743696
    14 1005 Children 66 0.606369
    8825 3339 War 19 0.444348

    Gráficos gêneros dos filmes, nº de avaliações e rating médio ponderado

    Gráfico Estático

    # Criar uma figura e uma grade de subplots com 1 linha e 2 colunas
    fig, axs = plt.subplots(1, 2, figsize=(21, 8))
    
    # Primeiro gráfico: rating médio ponderado
    barras1 = axs[0].barh(generos_ratings2['genres_separado'], generos_ratings2['rating_medio_ponderado'], color='#03647A')
    axs[0].invert_yaxis()  # Inverter a ordem dos gêneros
    axs[0].set_xlabel('Rating Médio (Ponderado)', fontsize=12)
    axs[0].set_ylabel('Gêneros de Filme', fontsize=12)
    axs[0].set_title('Os Gêneros de Filme com os maiores rating médio ponderado', fontsize=16, fontweight='bold')
    axs[0].grid(False)
    axs[0].set_frame_on(False)  # Remover a caixa ao redor do subplot
    axs[0].tick_params(axis='both', which='major', labelsize=14)
    
    # Definir explicitamente os ticks e rótulos no eixo y para o primeiro gráfico
    axs[0].set_yticks(range(len(generos_ratings2['genres_separado'])))
    axs[0].set_yticklabels(generos_ratings2['genres_separado'], fontweight='bold')
    
    # Adicionar rótulos às barras
    for barra in barras1:
        largura = barra.get_width()
        axs[0].text(largura, barra.get_y() + barra.get_height()/2, f'{largura:.2f}', va='center', ha='left', fontsize=10)
    
    # Segundo gráfico: número de avaliações por filme
    barras2 = axs[1].barh(generos_ratings2['genres_separado'], generos_ratings2['Numero_de_Avaliacoes_por_Filme'], color='#03647A')
    axs[1].invert_yaxis()  # Inverter a ordem dos gêneros
    axs[1].set_xlabel('Número de Avaliações por Filme', fontsize=12)
    axs[1].set_ylabel('Gêneros de Filme', fontsize=12)
    axs[1].set_title('Os Gêneros de Filme com os maiores números de avaliações', fontsize=16, fontweight='bold')
    axs[1].grid(False)
    axs[1].set_frame_on(False)  # Remover a caixa ao redor do subplot
    axs[1].tick_params(axis='both', which='major', labelsize=14)
    
    # Definir explicitamente os ticks e rótulos no eixo y para o segundo gráfico
    axs[1].set_yticks(range(len(generos_ratings2['genres_separado'])))
    axs[1].set_yticklabels(generos_ratings2['genres_separado'], fontweight='bold')
    
    # Adicionar rótulos às barras
    for barra in barras2:
        largura = barra.get_width()
        axs[1].text(largura, barra.get_y() + barra.get_height()/2, f'{largura:.0f}', va='center', ha='left', fontsize=10)
    
    # Ajustar o layout para evitar sobreposição
    plt.tight_layout()
    
    # Exibir os gráficos
    plt.show()
    

    </li>

    Gráfico Interativo

    import plotly.graph_objs as go
    import plotly.subplots as sp
    
    # Criar uma figura e uma grade de subplots com 1 linha e 2 colunas
    fig = sp.make_subplots(
        rows=1, cols=2, 
        subplot_titles=(
            'Gêneros com maior rating médio ponderado',
            'Gêneros com maior número de avaliações'
        ),
        horizontal_spacing=0.2,  # Aumentar o espaçamento horizontal entre os subplots
        vertical_spacing=0.02  # Espaçamento vertical entre os subplots
    )
    
    # Primeiro gráfico: rating médio ponderado
    fig.add_trace(go.Bar(
        x=generos_ratings2['rating_medio_ponderado'],
        y=generos_ratings2['genres_separado'],
        orientation='h',
        text=[f'{x:.2f}' for x in generos_ratings2['rating_medio_ponderado']],
        textposition='outside',
        marker=dict(color='#03647A')
    ), row=1, col=1)
    
    # Segundo gráfico: número de avaliações por filme
    fig.add_trace(go.Bar(
        x=generos_ratings2['Numero_de_Avaliacoes_por_Filme'],
        y=generos_ratings2['genres_separado'],
        orientation='h',
        text=[f'{x:.0f}' for x in generos_ratings2['Numero_de_Avaliacoes_por_Filme']],
        textposition='outside',
        marker=dict(color='#03647A')
    ), row=1, col=2)
    
    # Atualizar layout dos gráficos
    fig.update_layout(
        height=450,  # Ajustar a altura da figura
        width=900,
        showlegend=False,
        plot_bgcolor='white',
        margin=dict(t=50, b=50, l=50, r=50),  # Ajustar as margens
    )
    
    # Atualizar layout do primeiro subplot
    fig.update_xaxes(title_text='Rating Médio (Ponderado)', row=1, col=1)
    fig.update_yaxes(title_text='Gêneros de Filme', row=1, col=1, tickfont=dict(size=12, family='Arial, bold', weight='bold'))
    fig.update_yaxes(autorange="reversed", row=1, col=1)  # Inverter a ordem dos gêneros
    
    # Atualizar layout do segundo subplot
    fig.update_xaxes(title_text='Número de Avaliações por Filme', row=1, col=2)
    fig.update_yaxes(title_text='Gêneros de Filme', row=1, col=2, tickfont=dict(size=12, family='Arial, bold',weight='bold'))
    fig.update_yaxes(autorange="reversed", row=1, col=2)  # Inverter a ordem dos gêneros
    
    # Exibir o gráfico
    fig.show()
    
    # Salvar o gráfico como um arquivo HTML
    import plotly.io as pio
    pio.write_html(fig, file='Ranking_Generos_de_Filme.html', auto_open=True)
    

    8. De quais anos são os filmes mais assistidos? E os mais bem avaliados?

    Os filmes mais assistidos são dos anos de 1995, 1994, 1999, 1996 e 2000, respectivamente. Até 1992, a quantidade de avalições por ano cresce timidamente. Entre 1993 e 2000, ela cresce de forma significativa. E, a partir dos anos 2001, a quantidade de avaliações começa a diminuir.

    Os filmes mais bem avaliados são os de 1977, 1972, 1975, 1994 e 1980, respectivamente. Ao olhar o gráfico, vemos que as avalições médias por ano aumentam por volta de 1920 e continuam crescendo, com algumas oscilações até 2001.

    Os filmes mais bem avaliados são mais antigos, possivelmente, são os filmes considerados clássicos. Já os filmes mais assistidos são um pouco mais novos, entre os anos 90 e início dos anos 2000.Esta foi a época que a internet se popularizou, o que facilitou a divulgação midiática dos filmes.

    Em ambos os gráficos, o número de avalições por ano e a contagem de filmes assistidos diminui a partir dos anos 2000.
    De acordo com o site Britannica (history of film),no final do século XX houve um aumento da capacidade de animação por computador e de câmeras de vídeo digitais, isso fez com que muitos cineastas utilizassem tais tecnologias para reduzir os custos de produção.

    Além disso, nesta mesma época surgiu os DVDs, houve uma ampliação do acesso a TV a cabo e aos cinemas. Esses fatores contribuíram na internacionalização mercado cinematográfico. E com isso, os EUA ampliou seu domínio no cinema mundial. No final da década de 90, a produção de filmes nos EUA focou nos espectadores adolescentes, e de acordo com os críticos, isso diminuiu a qualidade dos filmes.


    Portanto, existem dois fatores que podem explicar a queda nos gráficos a partir dos anos 2000: Aumento do uso de tecnologia gráfica nos filmes e foco no público jovem.

    Preparando as tabelas

    Primeiro, vamos olhar as tabela que serão unidas

    movies_treino_transformado.head(3)
    
    movieId title genres Ano_do_filme titulo_sem_ano genres_separado
    0 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy 1995 Toy Story Adventure
    1 2 Jumanji (1995) Adventure|Children|Fantasy 1995 Jumanji Adventure
    2 3 Grumpier Old Men (1995) Comedy|Romance 1995 Grumpier Old Men Comedy
    ratings_treino_transformado.head(3)
    
    userId Numero_de_Avaliacoes_por_usuarios movieId Numero_de_Avaliacoes_por_Filme rating rating_medio_simples rating_medio_ponderado
    0 5 43 47 1567 5.0 4.057754 3.286254
    1 5 43 175 140 4.0 3.482143 1.258266
    2 5 43 257 104 4.0 3.341346 1.032082

    Vamos unir as tabelas

    # Unir as tabela e selecionar as colunas de interesse
    ano_filme_rating = pd.merge(movies_treino_transformado[['movieId','title','Ano_do_filme']], 
                                ratings_treino_transformado[['movieId', 'rating_medio_ponderado']], 
                                on="movieId", how="inner")
    ano_filme_rating.head()                             
    
    movieId title Ano_do_filme rating_medio_ponderado
    0 1 Toy Story (1995) 1995 3.264437
    1 1 Toy Story (1995) 1995 3.264437
    2 1 Toy Story (1995) 1995 3.264437
    3 1 Toy Story (1995) 1995 3.264437
    4 1 Toy Story (1995) 1995 3.264437

    Agora, vamos remover as linhas cujo "Ano_do_filme" é igual a -1, pois são as observações em que não foi possível extrair o ano do filme.

    # Remover linhas onde a coluna 'Ano_do_filme' tem valor -1
    ano_filme_rating1 = ano_filme_rating.loc[ano_filme_rating['Ano_do_filme'] != -1]  
    

    Faremos a contagem de avaliações por ano do filme.

    # Fazer a contagem
    contagem_movies = ano_filme_rating1[['Ano_do_filme']].value_counts(ascending=False).reset_index()
    contagem_movies.head()
    
    Ano_do_filme count
    0 1995 45559
    1 1994 39641
    2 1999 35463
    3 1996 33980
    4 2000 30310

    Será criada a coluna ratin_medio_por_ano

    # Agrupar os dados pela coluna 'Ano_do_filme' e calcular a média da coluna 'rating_medio_ponderado'
    rating_medio_por_ano1 = ano_filme_rating1.groupby('Ano_do_filme')['rating_medio_ponderado'].mean().reset_index()
    
    # Renomear a coluna de média para 'rating_medio_por_ano'
    rating_medio_por_ano1 = rating_medio_por_ano1.rename(columns={'rating_medio_ponderado': 'rating_medio_por_ano'})
    rating_medio_por_ano1.head()
    
    Ano_do_filme rating_medio_por_ano
    0 1878 0.098156
    1 1887 0.035130
    2 1895 0.133113
    3 1896 0.112191
    4 1897 0.084134

    A seguir temos a tabela final

    # Unir as tabelas 
    movies_ratings = pd.merge(rating_medio_por_ano1, contagem_movies, on="Ano_do_filme", how='inner' )
    movies_ratings 
    
    Ano_do_filme rating_medio_por_ano count
    0 1878 0.098156 1
    1 1887 0.035130 2
    2 1895 0.133113 8
    3 1896 0.112191 8
    4 1897 0.084134 3
    ... ... ... ...
    123 2019 0.917894 5966
    124 2020 0.448593 2484
    125 2021 0.420438 2104
    126 2022 0.421568 1477
    127 2023 0.184443 225

    128 rows × 3 columns

    Tabela com a contagem dos filmes mais assistidos

    Vamos criar a tabela com os filmes mais assistidos.

    movies_ratings_count = movies_ratings.sort_values(by='count',ascending=False)
    movies_ratings_count1 = movies_ratings_count.head(5)
    movies_ratings_count1.head()
    
    Ano_do_filme rating_medio_por_ano count
    99 1995 2.075816 45559
    98 1994 2.255304 39641
    103 1999 2.071166 35463
    100 1996 1.742998 33980
    104 2000 1.819669 30310

    Tabela dos filmes com as maiores avaliações

    movies_ratings_top = movies_ratings.sort_values(by='rating_medio_por_ano',ascending=False)
    movies_ratings_top1 = movies_ratings_top.head(5)
    movies_ratings_top1.head()
    
    Ano_do_filme rating_medio_por_ano count
    81 1977 2.413250 4823
    76 1972 2.335413 3452
    79 1975 2.311737 5111
    98 1994 2.255304 39641
    84 1980 2.200814 7491

    Gráfico

    # Ordenando por ano
    movies_ratings = movies_ratings.sort_values('Ano_do_filme')
    
    # Dados para o gráfico de rating médio por ano
    line_rating = go.Scatter(
        x=movies_ratings['Ano_do_filme'],
        y=movies_ratings['rating_medio_por_ano'],
        mode='lines+markers',
        name='Rating Médio',
        line=dict(color='#006868', width=2),
        marker=dict(size=8, color='#006868'),
    )
    
    # Destacar os 5 maiores anos de rating médio
    top_5_years_rating = movies_ratings.nlargest(5, 'rating_medio_por_ano')
    highlighted_points_rating = go.Scatter(
        x=top_5_years_rating['Ano_do_filme'],
        y=top_5_years_rating['rating_medio_por_ano'],
        mode='markers',
        name='Top 5 Anos',
        marker=dict(size=12, color='gold', symbol='star', line=dict(color='black', width=2)),
        showlegend=False,
    )
    
    # Dados para o gráfico de contagem por ano
    line_count = go.Scatter(
        x=movies_ratings['Ano_do_filme'],
        y=movies_ratings['count'],
        mode='lines+markers',
        name='Contagem',
        line=dict(color='#7D01D6', width=2),
        marker=dict(size=8, color='#7D01D6')
    )
    
    # Destacar os 5 maiores anos de contagem
    top_5_years_count = movies_ratings.nlargest(5, 'count')
    highlighted_points_count = go.Scatter(
        x=top_5_years_count['Ano_do_filme'],
        y=top_5_years_count['count'],
        mode='markers',
        name='Top 5 Anos',
        marker=dict(size=12, color='gold', symbol='star', line=dict(color='black', width=2)),
        showlegend=False,
    )
    
    # Criar figuras e subplots
    fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
                        subplot_titles=('Ano dos Filmes com as maiores avaliações', 'Ano dos Filmes mais assitidos'))
    fig.add_trace(line_rating, row=1, col=1)
    fig.add_trace(highlighted_points_rating, row=1, col=1)
    fig.add_trace(line_count, row=2, col=1)
    fig.add_trace(highlighted_points_count, row=2, col=1)
    
    # Atualizar layout do subplot de Rating Médio por Ano
    fig.update_xaxes(#title_text='Ano do Filme', 
                     tickangle=360, 
                     tickmode='linear', tick0=movies_ratings['Ano_do_filme'].min(), 
                     dtick=5, range=[movies_ratings['Ano_do_filme'].min(), movies_ratings['Ano_do_filme'].max()], row=1, col=1,
                     showgrid=True,gridcolor='rgba(0,0,0,0.1)',)
    fig.update_yaxes(title_text='Rating Médio por ano', row=1, col=1,showgrid=True,gridcolor='rgba(0,0,0,0.1)',)
    
    
    # Atualizar layout do subplot de Contagem por Ano
    fig.update_xaxes(title_text='Ano do Filme', tickangle=360, tickmode='linear',
                     tick0=movies_ratings['Ano_do_filme'].min(), dtick=5, range=[movies_ratings['Ano_do_filme'].min(), 
                     movies_ratings['Ano_do_filme'].max()], row=2, col=1,tickfont=dict(size=10),      
                     showgrid=True,gridcolor='rgba(0,0,0,0.1)',)
    fig.update_yaxes(title_text='Contagem', row=2, col=1,showgrid=True,gridcolor='rgba(0,0,0,0.1)',)
    
    # Atualizar layout da figura geral
    fig.update_layout(
        #title='Ano dos Filmes com as maiores avaliações e mais assistidos',
        title_font=dict(family='Arial', size=24, color='black', weight='bold'),
        width=1100,  # Definindo a largura da figura para 1500 pixels
        plot_bgcolor='white',
        #hovermode='x',
        margin=dict(l=50, r=50, t=50, b=50),
    )
    
    # Exibir o gráfico
    fig.show()
    
    # Salvar o gráfico como um arquivo HTML
    pio.write_html(fig, file='Ano_dos_Filmes_com_as_maiores_avaliacoes_e_mais_assistidos.html', auto_open=True)
    

    Insights

    1. Os usuários podem estar insatisfeitos com as recomendações do site

    A nota média dada pelo usuário (rating) foi de 3,52 (tópico 2) e essa média diminui conforme o usuário faz mais avaliações (tópicos 3 e 4). Além disso, o número de avaliações por usuário é baixo , a maioria faz 15 avaliações (tópico 3). Estes resultados, podem ser reflexo de uma insatisfação com as recomendações.

    Conforme indicado no tópico 3, seria interessante a MovieLens investigar o comportamento destes usuários para melhorar as recomendações e aumentar a retenção Para isso, o site poderia:

    • Analisar o número de avaliações vs média (rating) ao longo do tempo: Isto seria interessante para entender se existe um padrão temporal no uso do site MovieLens. Exemplo: por quanto tempo um usuário utiliza ativamente o site?
    • Fazer segmentações: o MovieLens poderia segmentar os usuários por idade e gênero para descobrir como as notas dadas variam em cada grupo e assim, pensar em recomendações personalizadas para cada segmento de usuário.
    • </ul>
      Espera-se que após estas análises, o MovieLens melhore a média de ratings e aumente o número de avaliações por usuário.

      2. Gêneros de destaque

      Os gêneros de filme Crime, Aventura e Mistério possuem as maiores notas e os maiores números de avaliações (tópico 7). Para empresas como a Netflix, esta é uma informação relevante para decidir em quais gêneros ela deve investir na hora de produzir um filme.

      3. Explorar diferentes de nichos

      1. Nicho: Filmes dos anos 90 – 2000

      Os filmes mais avaliados são do final da década de 90 e início dos anos 2000, principalmente dos gêneros Ação, Comédia e Crime (tópico 5)

      2. Nicho: Filmes clássicos

      Os filmes com as maiores avaliações são das décadas de 70 a 90, nos gêneros comédia, drama e crime (tópico 6). Em toda a análise, o gênero drama se destacou apenas neste nicho. Assim, se empresas como a Netflix buscam adquirir direitos autorais de dramas, devem considerar filmes clássicos.

      3. Sagas

      Apesar das sagas não aparecem no ranking dos filmes mais avaliados e com as maiores notas, as nuvens de palavras dos tópicos 4 e 5 mostram que as sagas ganham destaque quando consideradas em conjunto. Portanto, filmes de sagas podem ser um nicho interessante para aquisição de direitos autorais por plataformas de streaming.

      4. Nicho Jovem

      Conforme explicado no tópico 7, filmes propensos a violência (Crime, Aventura e Mistério) e que usam mais tecnologia, chamam atenção do público jovem.

      5. Nicho pessoas mais velhas

      O tópico 8 revela que a partir dos anos 2000 a média de avaliações por ano caiu, possivelmente devido à mudança de foco para o público jovem e ao uso excessivo de computação gráfica nos filmes. Em contraste com o nicho 4, este poderia se concentrar em filmes com menos efeitos visuais e que atendam a um público mais maduro, como filmes independentes.

      OBS: O dataset não tem informações sobre os usuários, isso limitou um pouco uma análise mais profunda. Se estas informações estivessem disponíveis, seria interessante analisar a relação de cada nicho de filme com os diferentes perfis de clientes/usuários.